package tom.vertx.core.demo01;

import io.vertx.core.*;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServer;
import lombok.extern.slf4j.Slf4j;
import tom.vertx.core.util.MainRunner;

/**
 * 此处实现异步启动start(promise) 还有同步启动方法start()
 * @author ZHUFEIFEI
 */
@Slf4j
public class HelloVerticle extends AbstractVerticle {

  @Override
  public void start(Promise<Void> startPromise) throws Exception {
    //创建http服务器，并监听启动事件, vertx是核心组件
    HttpServer http = vertx.createHttpServer().requestHandler(req -> {
      log.info("request => {}", req);
      //链式
      req.response()
        .putHeader("content-type", "text/plain")
        .end("Hello from Vert.x!");
      //方式2
//      HttpServerResponse response = req.response();
//      response.putHeader("content-type", "text/plain");
//      response.write("Hello 2");
//      response.end();
    }).listen(8888, result -> {
      if (result.succeeded()) {
        startPromise.complete();
        System.out.println("HTTP server started on port 8888");
      } else {
        startPromise.fail(result.cause());
      }
    });

    //context其实就是event-loop的context, 与event-loop thread绑定, 所以通过context执行操作都是同一个event-loop内的thread, thread来自worker pool
    if (context.isEventLoopContext()) {
      System.out.println("Context attached to Event Loop");
    } else if (context.isWorkerContext()) {
      System.out.println("Context attached to Worker Thread");
    } else if (context.isMultiThreadedWorkerContext()) {
      System.out.println("Context attached to Worker Thread - multi threaded worker");
    } else if (! Context.isOnVertxThread()) {
      System.out.println("Context not attached to a thread managed by vert.x");
    }
    //通过context异步执行
    vertx.getOrCreateContext().runOnContext( (v) -> {
      System.out.println("This will be executed asynchronously in the same context");
    });
    //不同的handler间共享数据
    context.put("data", "hello");
    context.runOnContext((v) -> {
      String hello = context.get("data");
      System.out.println("context data => " + hello);
    });

    //定时执行,如果任务比较耗时，可能会导致待执行的任务出现堆叠，所以如果比较耗时，可以使用setTime，执行完毕后再setTime
    long timerId = super.vertx.setPeriodic(5 * 1000, id -> {
      log.info("setPeriodic-{}", id);
    });

    //等效于setPeriodic的定时器，不过不会出现任务堆叠
    long timerId2 = super.vertx.setTimer(1000L, new Handler<Long>() {
      @Override
      public void handle(Long event) {
        log.info("setTimer-{} sleep.", event);
        sleep(3000L);
        vertx.setTimer(1000L, this);
      }
    });

    //阻塞任务将使用worker pool,默认会自动创建,可以手动配置
    WorkerExecutor executor = vertx.createSharedWorkerExecutor("my-work-pool", 1);
    //执行阻塞方法，但是阻塞方法不应执行时间太长, 调用该方法执行阻塞操作但是也是异步行为不会阻塞下面代码的执行
    vertx.executeBlocking(promise -> {
      sleep(3000L);
      promise.complete("execute block finished.");
    }, false, result -> {
      log.info("block result => {}", result.result());
    });
    //默认的work pool是20个线程，所以多次调用多个阻塞任务可以并行执行，第二个参数ordered如果无序则任务顺序将不会按照提交顺序执行
    vertx.executeBlocking(promise -> {
      sleep(1000L);
      promise.complete("execute block2 finished.");
    }, false, result -> {
      log.info("block2 result => {}", result.result());
    });
    log.info("executeBlocking over.");


    Future<String> f1 = Future.future(promise -> {
      sleep(1000L);
      promise.complete("ok");
    });
    Future<String> f2 = Future.future(promise -> {
      sleep(1000L);
      promise.fail("error");
    });
    //并行执行组合器, all(...)当所有都成功就成功, any(...)有一个成功就成功, join所有都执行结束
    CompositeFuture.all(f1, f2).setHandler(asyncResult -> {
      if (asyncResult.succeeded()) {
        log.info("All successed!");
      } else {
        log.info("At least one failed!");
      }
    });
    CompositeFuture.any(f1, f2).setHandler(asyncResult -> {
      if (asyncResult.succeeded()) {
        log.info("At least one successed!");
      } else {
        log.info("All failed!");
      }
    });
    CompositeFuture.join(f1, f2).setHandler(asyncResult -> {
      if (asyncResult.succeeded()) {
        log.info("All successed!");
      } else {
        log.info("All completed and At least one failed!");
      }
    });
    //串行执行链,操作串行执行
    io.vertx.core.file.FileSystem fs = vertx.fileSystem();
    Future.future(promise -> fs.createFile("D:/log/abc", res -> {
      log.info("create file => {}", res);
      //执行成功,触发下一个操作
      promise.complete(res);
    })).compose(v -> Future.future(promise -> fs.writeFile("D:/log/abc", Buffer.buffer("hello"), res -> {
      log.info("write file => {}", res);
      promise.complete(res);
    }))).compose(v -> Future.future(promise -> fs.move("D:/log/abc", "D:/log/cde", res -> {
      log.info("move file => {}", res);
      promise.complete(res);
    })));

    //测试verticle隔离, classloader都是AppClassloader
    log.info("classloader => {}", this.getClass().getClassLoader().toString());

    //此部分还可以放到stop方法内,当verticle被undeploy时触发
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
      //取消停止定时器, 此处支持演示手动取消定时器的方法, 对于在verticle内创建的定时器,在verticle undeploy后会自动取消. 见CloseHooks
      super.vertx.cancelTimer(timerId);
      super.vertx.cancelTimer(timerId2);
      //关闭work pool, 在verticle创建的work pool被undeploy时会自动close,此处演示
      executor.close();
      //关闭http server, 在verticle内创建的server,在undeploy时,会自动关闭, 此处演示
      http.close();
    }));
  }

  @Override
  public void stop(Future<Void> stopFuture) throws Exception {
    //清理操作
    super.stop(stopFuture);
  }

  public void sleep(long millis) {
    try {
      Thread.sleep(millis);
    } catch (InterruptedException e) {
    }
  }

  public static void main(String[] args) {
    //standard verticle
//    MainRunner.run("vertx-demo01/src/main/java/", HelloVerticle.class);

    //worker verticle, 同一时间只只会有一个worker线程在执行,不存在并发问题,执行的线程不同的时间可以不同.
    //与标准的verticle不同, worker verticle内所有的执行任务同一时间只会在一个线程执行,也就是串行执行, 不过执行的线程可以不同
//    MainRunner.run("vertx-demo01/src/main/java/", HelloVerticle.class,
//        null, new DeploymentOptions().setWorker(true)
//      );

    //multi-threaded worker类型,worker类型的并行形式, 设计用于并行消费event bus中的消息
    //setMultiThreaded废弃, 大多数应用不需要使用该类型
    MainRunner.run("vertx-demo01/src/main/java/", HelloVerticle.class, null,
      new DeploymentOptions()
        .setWorker(true)
        //部署verticle实例数, 与下面的workerPoolSize匹配
        .setInstances(6)
        .setWorkerPoolSize(6)
        .setWorkerPoolName("my-worker-pool")
    );


  }

}
